/*
  Copyright © 2010  Vinícius dos Santos Oliveira

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "scribbleelement.h"
#include <QGraphicsScene>
using namespace Touche;
#include <QColorDialog>
#include <QStateMachine>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QParallelAnimationGroup>
#include <QGraphicsSvgItem>
#include "widgets/imageitem.h"

// class ScribbleItem

static const QPointF neutralPos(0., 0.);
const QImage ScribbleItem::nullImage(":/gfx/png/null_scribble.png");

ScribbleItem::ScribbleItem(const QImage &image, QGraphicsItem *parentItem) :
        QGraphicsItem(parentItem),
        m_image(nullImage)
{
    QPainter painter(&m_image);
    painter.drawImage(neutralPos, image);
}

QRectF ScribbleItem::boundingRect() const
{
    return QRectF(neutralPos, m_image.size());
}

void ScribbleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    painter->drawImage(neutralPos, m_image);
}

void ScribbleItem::setImage(const QImage &image)
{
    m_image = nullImage;
    {
        QPainter painter(&m_image);
        painter.drawImage(neutralPos, image);
    }
    QGraphicsItem::update();
}

// class ScribbleElement

static const QString type("scribble");
static const QSize size(120, 120);
const QImage ScribbleElement::nullImage(":/gfx/png/null_image.png", "png");

ScribbleElement::ScribbleElement() :
        locked(false),
        image(nullImage),
        pen(QBrush(Qt::black), 2., Qt::SolidLine, Qt::RoundCap),
        m_item(new QGraphicsSvgItem(":/gfx/svg/item_draw.svg"))
{
}

const QString &ScribbleElement::type() const
{
    return ::type;
}

QRectF ScribbleElement::item(QGraphicsItem *parentItem) const
{
    m_item->setParentItem(parentItem);
    return m_item->boundingRect();
}

QVector<QString> ScribbleElement::menuOptions() const
{
    static const QVector<QString> defaultAction(1, "edit");
    if(locked){
        return QVector<QString>();
    }else{
        return defaultAction;
    }
}

void ScribbleElement::onMenuActived(const QString &option)
{
    if(option == "view"){
        // TODO
    }else{
        emit sceneRequest();
    }
}

static const QBrush background(QImage(":/gfx/png/scribble_background.png", "png"));

void ScribbleElement::onSceneReceived(QGraphicsScene *scene)
{
    scene->setBackgroundBrush(background);

    QAnimationGroup *majorAnimationGroup = new QParallelAnimationGroup();
    QAnimationGroup *animationGroup = new QSequentialAnimationGroup();

    scribbleArea = new ScribbleAreaItem(&image);
    scribbleArea->setPos(404., -180.);
    scene->addItem(scribbleArea);

    QPropertyAnimation *animation = new QPropertyAnimation(scribbleArea, "pos");
    animation->setEndValue(QPointF(194., 30.));
    animation->setEasingCurve(QEasingCurve::InOutQuint);
    animation->setDuration(550);
    majorAnimationGroup->addAnimation(animation);

    menu[0] = new PushButtonItem(":/gfx/svg/button-ok.svg");
    menu[1] = new PushButtonItem(":/gfx/svg/edit-clear.svg");
    menu[2] =  new PushButtonItem(":/gfx/svg/pen.svg");
    menu[3] = new PushButtonItem(":/gfx/svg/eraser.svg");
//    menu[4] = new PushButtonItem(":/gfx/svg/color-picker.svg"); This item must be removed

    menu[0]->setHasBg(true);
    menu[1]->setHasBg(true);
    menu[2]->setHasBg(true);
    menu[3]->setHasBg(true);

    animation = new QPropertyAnimation(menu[0], "scale");
    menu[0]->setPos(676., 33.);
    menu[0]->setScale(0.);
    animation->setDuration(400);
    animation->setEndValue(1.);
    animation->setEasingCurve(QEasingCurve::InOutElastic);
    animationGroup->addAnimation(animation);
    scene->addItem(menu[0]);

    animation = new QPropertyAnimation(menu[1], "scale");
    menu[1]->setPos(63., 33.);
    menu[1]->setScale(0.);
    menu[1]->setTransformOriginPoint(24., 12.);
    animation->setEasingCurve(QEasingCurve::OutElastic);
    animation->setEndValue(1.);
    animation->setDuration(400);
    animationGroup->addAnimation(animation);
    majorAnimationGroup->addAnimation(animationGroup);

    animationGroup = new QSequentialAnimationGroup();
    scene->addItem(menu[1]);

    animation = new QPropertyAnimation(menu[2], "scale");
    menu[2]->setPos(63., 111.);
    menu[2]->setScale(0.);
    menu[2]->setTransformOriginPoint(12., 24.);
    animation->setEasingCurve(QEasingCurve::OutBack);
    animation->setEndValue(1.);
    animation->setDuration(400);
    animationGroup->addAnimation(animation);
    menu[2]->setCheckable(true);
    menu[2]->setChecked(true);
    scene->addItem(menu[2]);

    animation = new QPropertyAnimation(menu[3], "scale");
    menu[3]->setPos(63., 189.);
    menu[3]->setScale(0.);
    menu[3]->setTransformOriginPoint(36., 48.);
    animation->setEndValue(1.);
    animation->setEasingCurve(QEasingCurve::OutInElastic);
    animation->setDuration(400);
    animationGroup->addAnimation(animation);
    majorAnimationGroup->addAnimation(animationGroup);
    menu[3]->setCheckable(true);
    scene->addItem(menu[3]);

//    animation = new QPropertyAnimation(menu[4], "scale");
//    menu[4]->setPos(56., 192.);
//    menu[4]->setScale(0.);
//    menu[4]->setTransformOriginPoint(48., 36.);
//    animation->setEndValue(1.);
//    animation->setEasingCurve(QEasingCurve::OutBounce);
//    animation->setDuration(400);
//    majorAnimationGroup->addAnimation(animation);
//    scene->addItem(menu[4]);
    majorAnimationGroup->start(QAbstractAnimation::DeleteWhenStopped);

    connect(menu[0], SIGNAL(clicked()), this, SLOT(onFinish()));
    connect(menu[1], SIGNAL(clicked()), scribbleArea, SLOT(clearImage()));
    connect(menu[1], SIGNAL(clicked()), this, SLOT(onPenButtonClicked()));
    connect(menu[2], SIGNAL(clicked()), this, SLOT(onPenButtonClicked()));
    connect(menu[3], SIGNAL(clicked()), this, SLOT(onEraserButtonClicked()));
//    connect(menu[4], SIGNAL(clicked()), this, SLOT(onColorChoose()));
}

void ScribbleElement::onElementLocked(bool locked)
{
    this->locked = locked;
}

void ScribbleElement::onFinish()
{
    if(scribbleArea->isNull()){
        scribbleArea->deleteLater();
        scribbleArea = NULL;
        emit stageRequest();
    }else{
        m_null = false;
        if(dynamic_cast<QGraphicsSvgItem *>(m_item)){
            QGraphicsItem *parent = m_item->parentItem();
            delete m_item;
            m_item = new ScribbleItem(image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), parent);
        }else{
            (reinterpret_cast<ScribbleItem *>(m_item))->setImage(image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
        }
        scribbleArea->deleteLater();
        scribbleArea = NULL;
        emit contentsChanged();
        emit stageRequest();
    }
}

void ScribbleElement::onPenButtonClicked()
{
    scribbleArea->setPen(pen);
    scribbleArea->setCompositionMode();
    menu[2]->setChecked(true);
    menu[3]->setChecked(false);
}

void ScribbleElement::onEraserButtonClicked()
{
    static QPen eraserPen(QBrush(Qt::transparent), 16., Qt::SolidLine, Qt::RoundCap);
    scribbleArea->setPen(eraserPen);
    scribbleArea->setCompositionMode(QPainter::CompositionMode_SourceIn);
    menu[2]->setChecked(false);
    menu[3]->setChecked(true);
//    scribbleArea->setCursor(QCursor(QPixmap(), 16., 16.));
}

//TODO: o diálogo deveria ocorrer na própria scene
void ScribbleElement::onColorChoose()
{
    pen.setColor(QColorDialog::getColor(penColor));
    scribbleArea->setPen(pen);
}
